﻿using System;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;

namespace EasyIot.WinApp
{
    /// <summary>
    /// 串口操作类
    /// </summary>
    public class SerialPortHelper
    {
        SerialPort m_serialPort; 
        LockHandle m_oHandle = new LockHandle();
        ByteBuffer m_bbRecv = new ByteBuffer();
        byte[] m_buffer = new byte[1024];
        bool m_bIsConnected;
        object m_lock = new object();
        int m_timeout_analysis = 50;  

        /// <summary>
        /// 判断端口是否打开
        /// </summary>
        public bool IsPortOpen()
        {
            if (m_serialPort != null && m_serialPort.IsOpen)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// 串口初始化及开启接收处理线程
        /// </summary>
        /// <param name="strPortName">串口号</param>
        /// <param name="iBaudRate">波特率</param>
        /// <param name="iParity">校验位</param>
        /// <param name="iDataBits">数据位</param>
        /// <param name="iStopBits">停止位</param>
        /// <param name="sn">链路标示符</param>
        public bool BeginWork(string strPortName, int iBaudRate, int iParity, int iDataBits, int iStopBits, ref string err)
        {
            bool ret = false;
            err = string.Empty;

            try
            {
                // 开启端口
                m_serialPort = new SerialPort(strPortName, iBaudRate, (Parity)iParity, iDataBits, (StopBits)iStopBits);
                //m_serialPort.ReadTimeout = 10;
                //m_serialPort.WriteTimeout = 10;
                m_serialPort.Open();
                m_bbRecv.Clear();
                m_bIsConnected = true;
                ret = true;
            }
            catch (Exception ex)
            {
                err = "[Error]<BeginWork>:Message:" + ex.Message + "\r\nStackTrace:" + ex.StackTrace;
            }
            return ret;
        }

        /// <summary>
        /// 发送串口数据
        /// </summary>
        /// <param name="obj">十六进制数组</param>
        public void Send(int cmd, byte[] sendBuffer, int waittime, ref string outMsg)
        {
            if (!m_bIsConnected) return;

            if (m_serialPort != null && m_serialPort.IsOpen)
            {
                lock (m_lock)
                {
                    // 数据发送
                    m_serialPort.Write(sendBuffer, 0, sendBuffer.Length);
                    m_bbRecv.Clear();
                }

                DataMgr.MainHandle.OnMessage("串口发送：" + DataHelper.ToHexString(sendBuffer, sendBuffer.Length, true));

                // 数据解析
                if (waittime > 0)
                {
                    int overtime = waittime + m_timeout_analysis;
                    int sleepTime = 50;
                    int sleepCount = overtime / sleepTime;
                    int i = 0; bool analysis = false;
                    while (i++ <= sleepCount)
                    {
                        analysis = DataReceived(cmd);
                        if (analysis) break;
                        Thread.Sleep(sleepTime); Application.DoEvents();
                    }

                    if (!analysis)
                    {
                        outMsg = "receive a timeout";
                        DataMgr.MainHandle.OnMessage("串口反馈超时");
                    }
                }
            }
        }

        bool DataReceived(int cmd)
        {
            if (!m_bIsConnected) return false;

            bool ret = false;

            lock (m_lock)
            {
                int iBytes = m_serialPort.BytesToRead;
                if (iBytes > 0 && iBytes <= m_buffer.Length)
                {
                    m_serialPort.Read(m_buffer, 0, iBytes);
                    //CCommondFunc.AppendLog("Recv Data:" + CCommondFunc.ToHexString(m_buffer, 0, iBytes));

                    DataMgr.MainHandle.OnMessage("串口接收：" + DataHelper.ToHexString(m_buffer, iBytes, true));

                    m_bbRecv.Put(m_buffer, 0, iBytes);
                    ret = m_oHandle.Process(cmd, m_bbRecv);
                }
            }

            return ret;
        }

        /// <summary>
        /// 结束串口运行及资源清理
        /// </summary>
        public bool EndWork(ref string err)
        {
            if (!m_bIsConnected) return true;

            bool ret = false;

            m_bIsConnected = false;

            try
            {
                m_serialPort.Close();
                m_serialPort = null;
                Dispose();
                ret = true;
            }
            catch (Exception ex)
            {
                err = "[Error]<EndWork>:" + ex.Message;
            }

            return ret;
        }

        ~SerialPortHelper()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
    }
}